﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Linq.Expressions;
using System.Diagnostics;
using System.Data.Linq.Mapping;
using System.Collections;
using Entity;
using System.Reflection;
namespace Data
{
    /// <summary>
    /// ＬＩＮＱ数据库操作基类
    /// </summary>
    public abstract class RepositoryBase
    {
        public RepositoryBase(DataContext db)
        {
            DB = db;
        }
        #region DBContext Object
        /// <summary>
        /// 可以使用的数据库连接对象
        /// [xxb]
        /// </summary>
        protected System.Data.Linq.DataContext DB { get; private set; }
        #endregion

        #region DBContext SubmitChanges
        /// <summary>
        /// XXB默认提交【重写时候可能需要写入自定义的类似约束的逻辑】
        /// </summary>
        protected virtual void SubmitChanges()
        {
            ChangeSet cSet = DB.GetChangeSet();
            if (cSet.Inserts.Count > 0
                || cSet.Updates.Count > 0
                || cSet.Deletes.Count > 0)
            {
                try
                {
                    DB.SubmitChanges(System.Data.Linq.ConflictMode.ContinueOnConflict);
                }
                catch (System.Data.Linq.ChangeConflictException)
                {
                    foreach (System.Data.Linq.ObjectChangeConflict occ in DB.ChangeConflicts)
                    {
                        // 使用当前数据库中的值，覆盖Linq缓存中实体对象的值  
                        occ.Resolve(System.Data.Linq.RefreshMode.OverwriteCurrentValues);
                        // 使用Linq缓存中实体对象的值，覆盖当前数据库中的值  
                        occ.Resolve(System.Data.Linq.RefreshMode.KeepCurrentValues);
                        // 只更新实体对象中改变的字段的值，其他的保留不变  
                        occ.Resolve(System.Data.Linq.RefreshMode.KeepChanges);
                    }
                    DB.SubmitChanges();
                }
            }
        }

        #endregion

        #region Get Entity and MetaTable

        /// <summary>
        /// 得到一个实体，根据条件
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="queryFunc"></param>
        /// <returns></returns>
        protected virtual TEntity GetEntity<TEntity>(params object[] keyValues) where TEntity : EntityBase
        {
            var mapping = DB.Mapping.GetTable(typeof(TEntity));
            var keys = mapping.RowType.IdentityMembers.Select((m, i) => m.Name + " = @" + i).ToArray();
            TEntity entityTEntity = DB.GetTable<TEntity>().Where(String.Join(" && ", keys), keyValues).FirstOrDefault();
            if (entityTEntity != null)
                DB.Refresh(System.Data.Linq.RefreshMode.OverwriteCurrentValues, entityTEntity);
            return entityTEntity;

        }
        /// <summary>
        /// 得到结果集，根据条件
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <param name="queryFunc"></param>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> GetEntities<TEntity>(Expression<Func<TEntity, bool>> queryFunc) where TEntity : class
        {
            Debug.Assert(queryFunc != null, "expression passed in is null");
            var results = DB.GetTable<TEntity>().Where(queryFunc);
            return results;
        }
        /// <summary>
        /// 得到所有结果集
        /// </summary>
        /// <typeparam name="TEntity"></typeparam>
        /// <returns></returns>
        protected virtual IQueryable<TEntity> GetEntities<TEntity>() where TEntity : class //Entity 
        {
            return DB.GetTable<TEntity>();
        }
        /// <summary>
        /// 得到数据库表或视图的抽象
        /// </summary>
        /// <param name="rowType"></param>
        /// <returns></returns>
        protected MetaTable GetMetaTable(Type rowType)
        {
            return DB.Mapping.GetTable(rowType);
        }


        #endregion

        #region Delete,Insert,Update Methodsb

        #region Delete entity
        /// <summary>
        /// 删除实体
        /// </summary>
        /// <param name="entity"></param>
        protected void DeleteEntity(EntityBase entity)
        {
            Type entityType = entity.GetType();
            MetaTable table = GetMetaTable(entityType);

            List<object> arguments = new List<object>();
            var primaryKeyColumns = (from dm in table.RowType.PersistentDataMembers
                                     where dm.IsPrimaryKey
                                     select dm).ToList();

            if (primaryKeyColumns.Count == 0)
            {
                throw new NotSupportedException("This method only support entities with primary keys.");
            }

            string query = GetDeleteStatment(table, entity.IsRealDeleted);

            foreach (var primaryField in primaryKeyColumns)
            {
                if (arguments.Count != 0)
                {
                    query += " AND ";
                }

                object val = entityType.GetProperty(primaryField.Name).GetValue(entity, null);
                query += GetEqualStatment(primaryField.MappedName, arguments.Count);
                arguments.Add(val);
            }

            DB.ExecuteCommand(query, arguments.ToArray());
        }
        /// <summary>
        /// 删除列表
        /// </summary>
        /// <param name="list"></param>
        protected void DeleteEntity(List<EntityBase> list)
        {
            list.ForEach(entity =>
            {
                this.DeleteEntity(entity);
            });
        }
        #endregion

        #region Update Entity
        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity"></param>
        protected void UpdateEntity(EntityBase entity)
        {
            Dictionary<string, object> changes = entity.GetChanges();

            if (!(changes != null && changes.Count > 0))
                return;

            //if (entity.IsAlreadySaved()) //一个对象只能保存一次，第二次保存时，会报异常
            //{
            //    throw new InvalidOperationException("An instance of an entity can only be used to save data once.");
            //}

            Type entityType = entity.GetType();
            MetaTable table = GetMetaTable(entityType);

            var persistentMembers = table.RowType.PersistentDataMembers;
            var primaryKeyColumns = (from dm in persistentMembers
                                     where dm.IsPrimaryKey
                                     select dm).ToList();

            if (primaryKeyColumns.Count == 0)
                throw new NotSupportedException("This method only supports entities with primary keys.");

            List<object> arguments = new List<object>();
            StringBuilder builder = new StringBuilder();

            foreach (KeyValuePair<string, object> change in changes)
            {
                if ((persistentMembers.Where(m => m.Name == change.Key && !m.IsAssociation && !m.IsPrimaryKey)).Count() != 1) //!m.IsPrimaryKey说明这个字段不能是主键
                    continue;

                if (arguments.Count != 0)
                    builder.Append(", ");

                if (change.Value != null)
                {
                    builder.Append(change.Key + " = {" + arguments.Count + "}");
                    arguments.Add(change.Value);
                }
                else
                {
                    builder.Append(change.Key + " = NULL ");
                }
            }

            if (builder.Length == 0)
                return;

            builder.Insert(0, "UPDATE " + table.TableName + " SET ");

            builder.Append(" WHERE ");
            bool firstPrimaryKey = true;

            foreach (var primaryField in primaryKeyColumns)
            {
                if (firstPrimaryKey)
                    firstPrimaryKey = false;
                else
                    builder.Append(" AND ");

                object val = entityType.GetProperty(primaryField.Name).GetValue(entity, null);
                builder.Append(GetEqualStatment(primaryField.MappedName, arguments.Count));
                arguments.Add(val);
            }

            entity.MarkEntitySaved();

            try
            {
                entity.OnModifyBefore(); //为更新注入记录日志的事件
                DB.ExecuteCommand(builder.ToString(), arguments.ToArray());
                entity.OnModifyAfter(entity.Log);
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex);
                throw;
            }
        }
        /// <summary>
        /// 更新实体列表
        /// </summary>
        /// <param name="list"></param>
        protected void UpdateEntity(List<EntityBase> list)
        {
            list.ForEach(entity =>
            {
                this.UpdateEntity(entity);
            });
        }
        #endregion

        #region Insert Entity
        /// <summary>
        /// 插入实体
        /// </summary>
        /// <param name="entity"></param>
        protected void InsertEntity(EntityBase entity)
        {
            if (entity == null)
                throw new ArgumentException("The database entity can not be null.");

            Type entityType = entity.GetType();
            MetaTable table = GetMetaTable(entityType);
            MetaDataMember identityDatamember = table.RowType.DBGeneratedIdentityMember;

            List<object> arguments = new List<object>();
            StringBuilder fieldbuilder = new StringBuilder();
            StringBuilder valuebuilder = new StringBuilder();

            fieldbuilder.Append("INSERT INTO " + table.TableName + " (");

            foreach (var member in table.RowType.PersistentDataMembers)
            {
                if (!member.IsAssociation && !member.IsDbGenerated)
                {
                    object value = entityType.GetProperty(member.Name).GetValue(entity, null);
                    if (value != null)
                    {
                        if (arguments.Count != 0)
                        {
                            fieldbuilder.Append(", ");
                            valuebuilder.Append(", ");
                        }

                        fieldbuilder.Append(member.MappedName);
                        valuebuilder.Append("{" + arguments.Count + "}");

                        arguments.Add(value);

                    }
                }
            }

            fieldbuilder.Append(") Values (");
            fieldbuilder.Append(valuebuilder.ToString());
            fieldbuilder.Append(");");

            if (identityDatamember != null)
            {
                fieldbuilder.AppendFormat("SELECT * From {1} Where {0} = (CONVERT(Int,SCOPE_IDENTITY())) ", identityDatamember.MappedName, table.TableName);
                IEnumerable result = DB.ExecuteQuery(entityType, fieldbuilder.ToString(), arguments.ToArray());

                foreach (var item in result)
                {
                    PropertyInfo property = entityType.GetProperty(identityDatamember.Name);
                    object pk = property.GetValue(item, null);
                    property.SetValue(entity, pk, null);
                }
            }
            else
            {
                DB.ExecuteCommand(fieldbuilder.ToString(), arguments.ToArray());
            }
        }
        /// <summary>
        /// 插入实体列表
        /// </summary>
        /// <param name="list"></param>
        protected void InsertEntity(List<EntityBase> list)
        {
            list.ForEach(entity =>
            {
                this.InsertEntity(entity);
            });
        }
        #endregion

        #region Private Methods
        private static string GetDeleteStatment(MetaTable table, bool IsRealDeleted)
        {

            var isDeletedColumn = (from dm in table.RowType.PersistentDataMembers
                                   where dm.MappedName == "Status"
                                   select dm).SingleOrDefault();

            string query;
            if (isDeletedColumn == null || IsRealDeleted)
            {
                query = @"DELETE " + table.TableName + " WHERE ";
            }
            else
            {
                query = @"UPDATE " + table.TableName + " SET Status=400 WHERE ";
            }
            return query;
        }
        private static string GetEqualStatment(string fieldName, int paramId)
        {
            return string.Format("{0} = {1}", fieldName, GetParamTag(paramId));

        }
        private static string GetParamTag(int paramId)
        {
            return "{" + paramId + "}";

        }
        #endregion
        #endregion

        #region System Logs
        /// <summary>
        /// 插入日志
        /// </summary>
        /// <param name="log"></param>
        public void InsertLog(EntityBase log)
        {
            //写日志DB.Insert(log);
            if (log != null)
                this.InsertEntity(log);
        }
        #endregion

        #region Events
        /// <summary>
        /// 实体插入之后的处理事件
        /// </summary>
        protected event Action InsertAfter;
        /// <summary>
        /// 触发InsertAfter事件
        /// </summary>
        protected void OnInsertAfter()
        {
            if (InsertAfter != null)
                InsertAfter();
        }
        /// <summary>
        /// 更新实体后要的处理事件
        /// </summary>
        protected event Action UpdateAfter;
        /// <summary>
        /// 触发UpdateAfter
        /// </summary>
        protected void OnUpdateAfter()
        {
            if (UpdateAfter != null)
                UpdateAfter();
        }

        /// <summary>
        /// 插入实体前的处理事件
        /// </summary>
        protected event Action InsertBefore;
        /// <summary>
        /// 触发InsertBefore
        /// </summary>
        protected void OnInsertBefore()
        {
            if (InsertBefore != null)
                InsertBefore();
        }

        /// <summary>
        ///更新实体前的处理事件
        /// </summary>
        protected event Action UpdateBefore;
        /// <summary>
        /// 触发UpdateBefore
        /// </summary>
        protected void OnUpdateBefore()
        {
            if (UpdateBefore != null)
                UpdateBefore();
        }
        /// <summary>
        /// 删除实体之前的处理事件
        /// </summary>
        protected event Action DeleteBefore;
        /// <summary>
        /// 触发DeleteBefore
        /// </summary>
        protected void OnDeleteBefore()
        {
            if (DeleteBefore != null)
                DeleteBefore();
        }
        /// <summary>
        /// 删除实体之后的处理事件
        /// </summary>
        protected event Action DeleteAfter;
        /// <summary>
        /// 触发DeleteAfter
        /// </summary>
        protected void OnDeleteAfter()
        {
            if (DeleteAfter != null)
                DeleteAfter();
        }
        #endregion
    }
}
